package cn.bincker.mycaptcha.basic.impl;

import cn.bincker.mycaptcha.CaptchaFactory;
import cn.bincker.mycaptcha.basic.CaptchaBackgroundCutter;
import cn.bincker.mycaptcha.basic.entity.MyAnswer;
import cn.bincker.mycaptcha.basic.entity.MyCaptcha;
import cn.bincker.mycaptcha.basic.properties.ImageCaptchaProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

@Slf4j
public abstract class AbstractCaptchaFactory<C extends MyCaptcha, A extends MyAnswer> implements CaptchaFactory<C, A> {
    protected final CaptchaBackgroundCutter backgroundCutter;
    protected final List<String> imageList;
    protected final Random random;
    private final File imageFilePath;

    protected AbstractCaptchaFactory(ImageCaptchaProperties properties, CaptchaBackgroundCutter backgroundCutter) {
        this.backgroundCutter = backgroundCutter;
        this.random = new Random();
        //扫描图片目录
        this.imageFilePath = properties.getImageFilePath();
        this.imageList = this.refreshBackgroundImage();
    }

    private List<String> refreshBackgroundImage(){
        Assert.isTrue(imageFilePath.exists(), "验证码图片目录不存在: path=" + imageFilePath.getAbsolutePath());
        Assert.isTrue(imageFilePath.isDirectory(), "验证码背景图片不是目录: path=" + imageFilePath.getAbsolutePath());
        var imageReadFormats = Arrays.asList(ImageIO.getReaderFormatNames());
        var imageFileArray = imageFilePath.list((file, s) -> file.canRead() && imageReadFormats.contains(StringUtils.getFilenameExtension(s)));
        Assert.isTrue(imageFileArray != null && imageFileArray.length > 0, "无验证码图片: path=" + imageFilePath.getAbsolutePath());
        return new ArrayList<>(List.of(imageFileArray));
    }

    /**
     * 读取背景图片
     */
    protected BufferedImage buildBackground(){
        var imageIndex = random.nextInt(imageList.size());
        var imageFile = new File(imageFilePath, imageList.get(imageIndex));
        while (!imageFile.exists()){
            log.warn("背景图片不存在：path={}", imageFile);
            synchronized (this){
                imageList.remove(imageIndex);
                if(imageList.size() < 1) {
                    imageList.addAll(refreshBackgroundImage());
                    if(imageList.size() < 1) throw new RuntimeException("验证码背景图片列表为空");
                }
            }
            imageIndex = random.nextInt(imageList.size());
            imageFile = new File(imageFilePath, imageList.get(imageIndex));
        }
        BufferedImage backgroundImage;
        try {
            backgroundImage = ImageIO.read(imageFile);
        } catch (IOException e) {
            throw new RuntimeException("读取验证码背景图片失败: path=" + imageFile.getAbsolutePath(), e);
        }
        return backgroundCutter.cut(backgroundImage);
    }
}
